#include "chat.hh"

Chat::Chat (Vector2d pos, Vector2d size, int histo_size)
  : Menu (pos, size),
    histo_size_ (histo_size),
    active_ (false)
{
  ActionQueue* aq = ActionQueue::Instance ();
  queue_ = aq->queue_get ();

  current_text_ = new TextImg ("", Vector2f (0, 0));
  curr_ = "";
  list_ = new std::list<TextImg*>;
  can_switch_ = true;
  num_line_ = 0;
  line_size_ = 0;
  hist_offset_ = 0;
  cur_offset_ = 0;
  width_line_ = 0;
  pos_line_ = 0;
  max_line_ = 0;
}

Chat::~Chat ()
{
  list_->clear ();
  delete list_;
}

void
Chat::activate ()
{
  SDL_EnableKeyRepeat(0, 100);
  cur_offset_ = 0;
  width_line_ = 0;
  pos_line_ = 0;
  max_line_ = 0;
  curr_ = "";
  //  SDL_WM_GrabInput (SDL_GRAB_OFF);
  //  SDL_ShowCursor (SDL_ENABLE);
  SDL_EnableUNICODE (SDL_ENABLE);
  active_ = true;
}

void
Chat::desactivate ()
{
  SDL_EnableKeyRepeat(100, 100);
  //  SDL_ShowCursor (SDL_DISABLE);
  //  SDL_WM_GrabInput (SDL_GRAB_ON);
  SDL_EnableUNICODE (SDL_DISABLE);
  active_ = false;

  if (curr_ != "")
    queue_->push (new ActionSendText (curr_));
}

void
Chat::switch_state ()
{ 
  if (can_switch_)
    {
      if (active_)
	desactivate ();
      else
	activate ();

      can_switch_ = false;
    }
}

void
Chat::erase_char ()
{
  if (cur_offset_ != 0)
    {
      int char_size = glutBitmapWidth (GLUT_BITMAP_HELVETICA_18, (unsigned char) curr_[cur_offset_ - 1]);

      if ((int) curr_.size () != max_line_)
	{
	  int new_char_size = glutBitmapWidth (GLUT_BITMAP_HELVETICA_18, (unsigned char) curr_[max_line_]);
	  if (width_line_ + new_char_size >= line_size_)
	    --max_line_;
	  else
	    width_line_ += new_char_size;
	}
      else
	--max_line_;
      curr_.erase (cur_offset_ - 1, 1);

      if ((int) cur_offset_ != pos_line_)
	width_line_ -= char_size;
      else
	--pos_line_;

      --cur_offset_;
    }
}

void
Chat::add_char (unsigned char c)
{
  std::string before = curr_.substr (0, cur_offset_);
  std::string after = curr_.substr (cur_offset_);

  before += c;
  before += after;
  curr_ = before;

  int char_size = glutBitmapWidth (GLUT_BITMAP_HELVETICA_18, (unsigned char) c);

  // if the character makes the string too long
  if (width_line_ + char_size >= line_size_)
    {
      int tmp_width = 0;
      int i = 0;

      if ((int) cur_offset_ == max_line_)
	{
	  i = pos_line_;

	  for (; i < (int) curr_.size () && tmp_width < char_size; ++i)
	    tmp_width += glutBitmapWidth (GLUT_BITMAP_HELVETICA_18, (unsigned char) curr_[i]);
	  pos_line_ = i;
	  ++max_line_;
	  width_line_ = width_line_ + char_size - tmp_width;
	}
      else
	{
	  i = max_line_ - 1;

	  for (; i >= 0 && tmp_width < char_size; --i)
	    tmp_width += glutBitmapWidth (GLUT_BITMAP_HELVETICA_18, (unsigned char) curr_[i]);
	  max_line_ = i + 2;
	  width_line_ = width_line_ + char_size - tmp_width;
	}
    }
  else
    {
      ++max_line_;
      width_line_ += char_size;
    }

  ++cur_offset_;

}

void
Chat::move_cursor_left ()
{
  if (cur_offset_)
    {

      if ((int) cur_offset_ == pos_line_)
      	{
      	  int char_size = glutBitmapWidth (GLUT_BITMAP_HELVETICA_18, (unsigned char) curr_[pos_line_ - 1]);
      	  int tmp_width = 0;
      	  int i = max_line_ - 1;

      	  if (width_line_ + char_size >= line_size_)
      	    {
      	      for (; i >= (int) cur_offset_ && tmp_width < char_size; --i)
      		tmp_width += glutBitmapWidth (GLUT_BITMAP_HELVETICA_18, (unsigned char) curr_[i]);

      	      max_line_ = i + 1;
      	    }

	  --pos_line_;
	  width_line_ = width_line_ - tmp_width + char_size;
	}
      --cur_offset_;
    }
}

void
Chat::move_cursor_right ()
{
  if (cur_offset_ != curr_.size ())
    {
      if ((int) cur_offset_ == max_line_)
	{
	  int char_size = glutBitmapWidth (GLUT_BITMAP_HELVETICA_18, (unsigned char) curr_[max_line_]);
	  int tmp_width = 0;
	  int i = pos_line_;

	  if (width_line_ + char_size >= line_size_)
	    {
	      for (; i <= (int) cur_offset_ && tmp_width < char_size; ++i)
		tmp_width += glutBitmapWidth (GLUT_BITMAP_HELVETICA_18, (unsigned char) curr_[i]);

	      pos_line_ = i;
	    }

	  ++max_line_;
	  width_line_ = width_line_ - tmp_width + char_size;
	}

	++cur_offset_;
    }
}

void
Chat::dispatch () const
{
  glBegin(GL_QUADS);
  glColor3ub(255,0,0);
  glVertex2d(base_ (0), base_ (1));
  glVertex2d(base_ (0), end_ (1));
  glVertex2d(end_ (0), end_ (1));
  glVertex2d(end_ (0), base_ (1));
  glEnd();

  if (active_)
    {
      // cursor
      std::string tmp = curr_.substr (pos_line_, cur_offset_ - pos_line_);
      int size_px = glutBitmapLength (GLUT_BITMAP_HELVETICA_18, (unsigned char*) tmp.c_str ());
      glBegin(GL_LINE);
      glColor3ub(0,0,255);
      glVertex2d(base_ (0) + 10 + size_px, end_ (1) - 28);
      glVertex2d(base_ (0) + 10 + size_px, end_ (1) - 10);
      glEnd();

      glColor3ub(255,0,0);
      tmp = curr_.substr (pos_line_, max_line_ - pos_line_);
      current_text_->text (tmp);
      current_text_->dispatch ();
    }

  std::list<TextImg*>::const_iterator it = list_->begin ();

  Vector2f pos (base_ (0) + 10, end_ (1) - 30);

  unsigned int i = 0;
  for (; i < hist_offset_; ++i)
    ++it;

  for (; i < hist_offset_ + num_line_ && it != list_->end (); ++it, ++i)
    {
      (*it)->pos (pos);
      pos (1, pos (1) - 20);
      (*it)->dispatch ();
    }
}

void
Chat::new_msg (const std::string& msg)
{
  if (glutBitmapLength (GLUT_BITMAP_HELVETICA_18, (unsigned char*) msg.c_str ()) > line_size_)
    {
      unsigned int i = 0;
      unsigned int offset = 0;

      while (i < msg.length ())
	{
	  int size = 0;
	  while (size < line_size_ && i < msg.length ())
	    {
	      size += glutBitmapWidth (GLUT_BITMAP_HELVETICA_18, msg[i]);
	      ++i;
	    }

	  std::string tmp;
	  if (i != msg.length ())
	    tmp = msg.substr (offset, i - offset - 1);
	  else
	    tmp = msg.substr (offset, i - offset);
	  TextImg* t = new TextImg (tmp, Vector2f (0, 0));
	  if (list_->size () == histo_size_)
	    list_->resize (histo_size_ - 1);
	  list_->push_front (t);
	  offset = i - 1;
	}
    }
  else
    {
      TextImg* t = new TextImg (msg, Vector2f (0, 0));

      if (list_->size () == histo_size_)
	list_->resize (histo_size_ - 1);
      list_->push_front (t);
    }

  hist_offset_ = 0;
}

void
Chat::size_max_set (Vector2d size_max)
{
  size_max_ = size_max;

  Vector2d base (pos_ (0) * size_max_ (0) / 100,
		 pos_ (1) * size_max_ (1) / 100);
  Vector2d end ((pos_ (0) + size_ (0)) * size_max_ (0) / 100,
		(pos_ (0) + size_ (0)) * size_max_ (1) / 100);
  base_ = base;
  end_ = end;

  current_text_->pos (Vector2f (base_ (0) + 10, end_ (1) - 10));

  num_line_ = ((end_ (1) - base_ (1)) / 20) - 2;
  line_size_ = end_ (0) - base_ (0) - 35;
}

void
Chat::hoover_action (Vector2d cursor)
{
  (void) cursor;
}

void
Chat::click_action (Vector2d cursor, unsigned int button)
{
  if (list_->size () >= (unsigned int) num_line_)
    {
      if (button == 4 && hist_offset_ + num_line_ < list_->size ())
	++hist_offset_;
      else if (button == 5 && hist_offset_)
	--hist_offset_;
    }
  (void) cursor;
  (void) button;
}
